package java2021_9_23;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

//使用这个类,来封装数据库建立连接的逻辑
//1.创建好DataSource实例
//2.根据DataSource 创建对应的Connection
public class DButil {
    /**
     * private static final
     * 此处我们定义的变量,期望都是常量.
     * 这个是定义常量的惯用写法
     * 给常量定义,会惯用全大写的写法
     */
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java100_bookmanager?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "109614";

//  按这样的写法,如果有多个DBUtil的实例,就会同样有多个DataSource实例.
//    实际上,并不需要有多个DataSource实例
//    private DataSource dataSource = new MysqlDataSource();
    //如果在代码里只创建一个DBUtil实例,不多创建.但这必须通过人来保证这个事情(人是很容易出错的)
//    是否有办法,让程序/计算机,来保证DataSource实例只有一个呢?
//    --"单例模式".常用的一种设计模式

//---- 饿汉模式的代码
    private static DataSource dataSource = new MysqlDataSource();
//  加上static之后,DataSoure就变成了类属性,和实例无关了,只是和类相关.
//    意思是new创建实例,不会影响.而是变成和类相关了
    /**
     * 类属性,就是在类被创建出来的时候,才会被创建(啥时候创建类?类加载阶段,而对于
     * 类加载来说,一个类只是被加载一次)
     * 实例属性,就是在每个实例被创建出来的时候都会被创建
     *
     * 单例模式就是依赖了static类属性这样的特性
     * 由于类本身在程序中就是唯一的存在.类的属性同样也是程序中唯一的存在.
     * 后续调用也是返回之前的实例
     */
    /**
     *     private static DataSource dataSource = new MysqlDataSource();
     *     此处的dataSource 实例是在类加载阶段进行实例化的.(很早的阶段,程序一启动,大概率就会触发DBUtil的类加载)
     *     把这种风格的单例模式成为"饿汉模式"
     *
     *     还有另外一种风格,成为"懒汉模式"
     *     懒汉模式是知道第一次使用这个类的时候才会实例化.
     *     实例化时机回避饿汉模式更迟(延时加载)
     */
    //设置属性
//    使用一个构造方法来针对DataSource进行设置属性,是否可行? 答案是不行.
//    因为构造方法是需要实例化对象的,而我们现在不希望实例化

    //使用静态代码块
    //类加载阶段会调用静态代码块逻辑
    static{
        ((MysqlDataSource)dataSource).setUrl(URL);
        ((MysqlDataSource)dataSource).setUser(USERNAME);
        ((MysqlDataSource)dataSource).setPassword(PASSWORD);
    }
    //懒汉模式的代码
    //private static DataSource dataSource = null;

    //初始情况下,dataSource 是 null,没有被实例化,
//    首次调用getDataSource的时候,才会实例化.
//    如果程序中都没有用到getDataSource，就永远不需要实例化

//    private static DataSource getDataSource(){
//        if(dataSource == null){
//            ((MysqlDataSource)dataSource).setUrl(URL);
//            ((MysqlDataSource)dataSource).setUser(USERNAME);
//            ((MysqlDataSource)dataSource).setPassword(PASSWORD);
//        }
//        return dataSource;
//    }



    //提供一个方法,来连接
//    Connection connection = dataSource.getConnection();
    //这个方法也设计成static,此时不比创建DBUtil实例,就可以调用这个方法,这样用起来更方便一些
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();//饿汉模式
//         return getDataSource().getConnection();//懒汉模式
    }
    //释放资源
//    释放资源的顺序，要和申请的资源的顺序相反
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        //一旦某个环节出现了异常,不会引起后面的关闭操作执行不到
//        if(resultSet != null){
//            try{
//               resultSet.close();
//            }catch (SQLException e){
//                e.printStackTrace();
//            }
//        }
//        if(statement != null){
//            try{
//                statement.close();
//            }catch(SQLException e){
//                e.printStackTrace();
//            }
//        }
//        if(connection != null){
//            try{
//                connection.close();
//            }catch (SQLException e){
//                e.printStackTrace();
//            }
//        }
        /**
         * 上面这种代码更科学一些.更加严谨
         * 下面的代码,如果第一个就出现异常,则会直接跳过2和3,使得这两个无法正常关闭
         */
        //虽然这个写法,可能在出现异常的时候,可能会引起其他对象没有关闭
//        但我们认为这是一个小概率事件,因此就不考虑那么多了
        try{
            if(resultSet != null){
                resultSet.close();
            }
            if(statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        }catch (SQLException e){
            e.printStackTrace();
        }

    }
    /**
     * 类似于这类差别,在异常相关的代码中是比较常见的.
     * 主要是异常机制涉及到代码的"跳跃执行"
     * 跳跃很容易打破原有的逻辑
     */
}
